package pathways.Database.Specialized.Visual;

/**
 * Title:        Pathways
 * Description:  Pure Java version of the Pathways Project.
 * Copyright:    Copyright (c) 2002
 * Company:      Ants Technologies
 * @author Veejay Sani
 * @version 1.0
 */

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;

import pathways.CEnzyme;
import pathways.CReaction;
import pathways.CSubstrate;
import pathways.Database.Implementation.CDatabase;
import pathways.util.CUtil;
import pathways.util.Debug.CDebug;

public class CDBSVSearchBySubstrate extends JDialog
{
  JScrollPane scrollPaneEnzyme = new JScrollPane();
  JScrollPane scrollPaneProduct = new JScrollPane();
  JList enzymeList = new JList();
  JList prodList = new JList();
  JLabel lblSubstrate = new JLabel();
  JLabel lblEnzyme = new JLabel();
  JLabel lblProduct = new JLabel();
  JButton cmdOK = new JButton();
  JButton cmdCancel = new JButton();

  // my vars
  private CSubstrate substrate;
  private int connectingFrom;
  private int connectingTo;
  private Rectangle prodRect;
  private CDatabase db;
  private JList searchByList;
  private CEnzymeListModel enzymeListModel;
  private CProductListModel productListModel;
  private CReaction rxn;
  private int[] mnlastRxnIDs = {0};
  
  public CDBSVSearchBySubstrate(CSubstrate sub, int connectingFrom, 
                                int connectingTo, Rectangle prodRectangle,
                                CDatabase database, JFrame owner, int[] lastRxnIDs)
  {
    super(owner,"Search Reaction",true);
    
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
        
    substrate = sub;
    this.connectingFrom = connectingFrom;
    this.connectingTo = connectingTo;
    prodRect = prodRectangle;
    db = database;
    rxn = null;
    this.lblSubstrate.setText("Substrate:  " + sub.getName());
    this.mnlastRxnIDs = lastRxnIDs;
    
    ResultSet rsEnzymes = db.getSelect().getEnzymesBySubstrateAndProduct(substrate.getID(),0,mnlastRxnIDs);
    ResultSet rsProducts = db.getSelect().getProdcutsBySubstrateAndEnzyme(substrate.getID(),0,mnlastRxnIDs);
    
    enzymeListModel = new CEnzymeListModel(rsEnzymes,2);      
    enzymeList.setModel(enzymeListModel);
    
    productListModel = new CProductListModel(rsProducts,2);
    prodList.setModel(productListModel);
    
    setSize(600,400);    
  }
  
  private void jbInit() throws Exception
  {
    this.setResizable(false);
    this.addWindowListener(new java.awt.event.WindowAdapter()
    {
      public void windowOpened(WindowEvent e)
      {
        this_windowOpened(e);
      }
    });
    this.getContentPane().setLayout(null);
    scrollPaneEnzyme.setBounds(new Rectangle(17, 65, 266, 254));
    scrollPaneProduct.setBounds(new Rectangle(307, 64, 266, 254));
    lblSubstrate.setFont(new java.awt.Font("Dialog", 1, 16));
    lblSubstrate.setForeground(Color.black);
    lblSubstrate.setHorizontalAlignment(SwingConstants.CENTER);
    lblSubstrate.setText("Substrate");
    lblSubstrate.setBounds(new Rectangle(18, 6, 552, 26));
    lblEnzyme.setHorizontalAlignment(SwingConstants.CENTER);
    lblEnzyme.setText("Enzyme:");
    lblEnzyme.setBounds(new Rectangle(17, 41, 264, 22));
    lblProduct.setBounds(new Rectangle(307, 40, 264, 22));
    lblProduct.setText("Product:");
    lblProduct.setHorizontalAlignment(SwingConstants.CENTER);
    cmdOK.setText("OK");
    cmdOK.setBounds(new Rectangle(229, 333, 64, 26));
    cmdOK.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdOK_actionPerformed(e);
      }
    });
    cmdCancel.setBounds(new Rectangle(300, 333, 83, 26));
    cmdCancel.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdCancel_actionPerformed(e);
      }
    });
    cmdCancel.setText("Cancel");
    enzymeList.addListSelectionListener(new javax.swing.event.ListSelectionListener()
    {
      public void valueChanged(ListSelectionEvent e)
      {
        enzymeList_valueChanged(e);
      }
    });
    prodList.addListSelectionListener(new javax.swing.event.ListSelectionListener()
    {
      public void valueChanged(ListSelectionEvent e)
      {
        prodList_valueChanged(e);
      }
    });
    this.getContentPane().add(lblSubstrate, null);
    this.getContentPane().add(scrollPaneEnzyme, null);
    this.getContentPane().add(scrollPaneProduct, null);
    scrollPaneProduct.getViewport().add(prodList, null);
    scrollPaneEnzyme.getViewport().add(enzymeList, null);
    this.getContentPane().add(lblEnzyme, null);
    this.getContentPane().add(lblProduct, null);
    this.getContentPane().add(cmdCancel, null);
    this.getContentPane().add(cmdOK, null);
  }

  void cmdOK_actionPerformed(ActionEvent e)
  {
    if (isOK())
    {
      rxn = prepareReaction(substrate,getSelectedEnzyme(),getSelectedProduct());
      this.hide();
    }
  }

  private void selectIfOnlyOneItemInLists()
  {
    // if both selected then return
    // if one enz and one prod then select both
    // if enz selected then select if one prod
    // if prod selected then select if one enz
    int enzymeIndex = this.enzymeList.getSelectedIndex();
    int prodIndex = this.prodList.getSelectedIndex();
     
    if (enzymeIndex >= 0 && prodIndex >= 0)
       return;
       
    int enzymeCount = this.enzymeList.getModel().getSize();
    int prodCount = this.prodList.getModel().getSize();
    
    if (enzymeCount == 1 && prodCount == 1)
    {
      this.enzymeList.setSelectedIndex(0);
      this.prodList.setSelectedIndex(0);
    }
    
    if (enzymeIndex >= 0 && prodCount == 1)
    {
       this.prodList.setSelectedIndex(0);
       return;
    }
    
    if (prodIndex >=0 && enzymeCount == 1)
    {
      this.enzymeList.setSelectedIndex(0);
      return; 
    }
    
  }
  
  void cmdCancel_actionPerformed(ActionEvent e)
  {
    rxn = null;
    this.hide();
  }

  private CReaction prepareReaction(CSubstrate sub, CEnzyme enzyme, CSubstrate prod)
  {
    ResultSet rs = db.getSelect().getReaction(sub.getID(),enzyme.getID(),prod.getID());
    int rxnID = 0;
    CReaction reaction = null;
    
    try{    
      if (rs.next())
      {
        //System.out.println("Row = " + rs.getRow());
        rxnID = rs.getInt(1);   
      }
    } catch(SQLException exp)
    {
      CDebug.println(this,"prepareReaction() failed. Error: " + exp.toString());  
    }
    
    if (rxnID > 0)
    {
      reaction = new CReaction(sub,enzyme,prod,connectingFrom,connectingTo,rxnID);
      reaction.read(rxnID,db);   
    }
    
    return reaction;
  }
  
  public CReaction getReaction()
  {
    return rxn;  
  }
  
  private boolean isOK()
  {
    boolean bOK = true;
    
    selectIfOnlyOneItemInLists();
    
    if (enzymeList.getSelectedIndex() < 0)
    {
      bOK = false;
      JOptionPane.showMessageDialog(this,"Please select an Enzyme");  
    }
    
    if (bOK && prodList.getSelectedIndex() < 0)
    {
      bOK = false;
      JOptionPane.showMessageDialog(this,"Please select a product."); 
    }
    
    return bOK;
  }
  
  private CSubstrate getSelectedProduct()
  {
    int selectedIndex = prodList.getSelectedIndex();
    CSubstrate product = null;
    
    if (selectedIndex >=0)
    {
      ResultSet rs = productListModel.getData();
      
      try{
        rs.absolute(selectedIndex + 1);
        
        product = new CSubstrate(rs.getString(2), rs.getLong(1),prodRect);
        
      } catch(SQLException excep) {}
    }
    
    return product;
  }
  
  private CEnzyme getSelectedEnzyme()
  {
    int selectedIndex = enzymeList.getSelectedIndex();
    CEnzyme enzyme = null;
    
    if (selectedIndex >=0)
    {
      ResultSet rs = enzymeListModel.getData();
      
      try{
        rs.absolute(selectedIndex + 1);
        
        enzyme = new CEnzyme(rs.getString(2), rs.getLong(1));
        
      } catch(SQLException excep) 
      {
        CDebug.println(this,"getSelectedEnzyme() method failed. Error: " + excep.toString() );
      }
    }
    
    return enzyme;
  }  
    
  void enzymeList_valueChanged(ListSelectionEvent e)
  {
    int selectedIndex = enzymeList.getSelectedIndex();
      
    if (prodList.getSelectedIndex() < 0 && selectedIndex >= 0)
       searchByList = enzymeList;
    
    if (searchByList == enzymeList)
    {
      // reload the product list
      // get Ennzyme ID
      ResultSet rs = enzymeListModel.getData();
      long enzymeID = 0;
      
      try{
        rs.absolute(selectedIndex + 1);
        enzymeID = rs.getLong(1);
      } catch(SQLException excep) 
      {
        CDebug.println(this,"valueChanged() failed. Error: " + excep.toString());
      }
      
      // make new data for product list
      ResultSet rsProds = db.getSelect().getProdcutsBySubstrateAndEnzyme(substrate.getID(),enzymeID,mnlastRxnIDs);
      productListModel = new CProductListModel(rsProds,2);        
      prodList.setModel(productListModel);                        
    }     
  }

  void prodList_valueChanged(ListSelectionEvent e)
  {
    int selectedIndex = prodList.getSelectedIndex();
      
    if (enzymeList.getSelectedIndex() < 0 && selectedIndex >= 0)
       searchByList = prodList;
    
    if (searchByList == prodList)
    {
      // reload the product list
      // get Ennzyme ID
      ResultSet rs = productListModel.getData();
      long productID = 0;
      
      try{
        rs.absolute(selectedIndex + 1);
        productID = rs.getLong(1);
      } catch(SQLException excep) 
      {
        CDebug.println(this,"valueChanged() failed. Error: " + excep.toString());
      }
      
      // make new data for enzyme list
      rs = db.getSelect().getEnzymesBySubstrateAndProduct(substrate.getID(),productID,mnlastRxnIDs);
      enzymeListModel = new CEnzymeListModel(rs,2);        
      enzymeList.setModel(enzymeListModel);                        
    }     
  }

  void this_windowOpened(WindowEvent e)
  {
    if (this.enzymeListModel.getSize() == 0 && this.productListModel.getSize() == 0)
    {
      JOptionPane.showMessageDialog(this,"No more reactions found.","Warning",JOptionPane.WARNING_MESSAGE);
      rxn = null;
      this.dispose();
    }
  }
}

class CEnzymeListModel extends AbstractListModel
{
  public CEnzymeListModel(ResultSet set, int column)
  {
    rs = set;
    this.column = column;
    
    try
    {
      size = CUtil.getResultSetRowCount(rs);
    }
    catch(SQLException e)
    {
       CDebug.println(this, "Unable to get the size of the recordset. Error: " + e.toString());
       
       System.err.println("Fatal Error: Connection to database was lost. Please try again.");
              
       size = 0;
    }
  }
  
  public Object getElementAt(int index)
  {
    try
    {
      rs.absolute(index+1);
      return rs.getObject(column);
    }
    catch (SQLException e)
    {
      System.err.println("Fatal Error: Connection to database was lost.  Please try again.");
    }
    
    return null;
  }
  
  public int getSize()
  {      
    return size;
  }
  
  public ResultSet getData()
  {
    return rs;
  }
  
  private ResultSet rs;
  private int size;
  private int column;
}

class CProductListModel extends AbstractListModel
{
  public CProductListModel(ResultSet set, int column)
  {
    rs = set;
    this.column = column;
       
    try
    {
      size = CUtil.getResultSetRowCount(rs);
    }
    catch(SQLException e)
    {
       CDebug.println(this, "Unable to get the size of the recordset. Error: " + e.toString());
       
       System.err.println("Fatal Error: Connection to database was lost. Please try again.");
              
       size = 0;
    }
  }
  
  public Object getElementAt(int index)
  {
    try
    {
      rs.absolute(index+1);
      return rs.getObject(column);
    }
    catch (SQLException e)
    {
      System.err.println("Fatal Error: Connection to database was lost.  Please try again.");
    }
    
    return null;
  }
  
  public int getSize()
  {      
    return size;
  }

  public ResultSet getData()
  {
    return rs;
  }
  
  private ResultSet rs;
  private int size;
  private int column;
}

